/***********************************************************************
 * nScreen - An Advanced Console Application Framework for .NET
 * 
 * Copyright (C) 2007 by:
 *  Justin Long (dukk(a)dukk.org)
 *  Fabio Cavalcante (fabio(a)codesapien.com)
 *  Josh Perry (josh(a)6bit.com)
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Library General Public License as 
 * published by  the Free Software Foundation; either version 2 of the 
 * License or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Library General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this package (See COPYING.LIB); if not, write to the 
 * Free Software Foundation, Inc.
 * 59 Temple Place - Suite 330
 * Boston, MA 02111-1307, USA.
 ***********************************************************************/

using System;
using System.Collections.Generic;
using System.Text;

namespace nScreen.Controls
{
	public abstract class ScreenControl
	{
		private int _top = 0;
		private int _left = 0;

		private ScreenControl _parent;
		private ScreenControlCollection _controls;

		public event EventHandler Initialize;
		public event EventHandler Render;

		public ScreenControl() 
		{
			this.Controls = new ScreenControlCollection();
			this.Controls.ControlAdded += new EventHandler<ScreenControlEventArgs>(Controls_ControlAdded);
			this.Controls.ControlRemoved += new EventHandler<ScreenControlEventArgs>(Controls_ControlRemoved);
			this.Controls.Cleared += new EventHandler<ScreenControlCollectionClearedEventArgs>(Controls_Cleared);
		}

		public int Top
		{
			get { return _top; }
			set
			{
				_top = value;

				this.InvalidateScreen();
			}
		}

		public int Left
		{
			get { return _left; }
			set
			{
				_left = value;

				this.InvalidateScreen();
			}
		}

		public ScreenControl Parent
		{
			get { return _parent; }
			internal set { _parent = value;	}
		}

		public ScreenControlCollection Controls
		{
			get { return _controls; }
			set { _controls = value; }
		}

		internal void DoInitialize()
		{
			this.OnInitialize();
		}

		internal void DoRender()
		{
			this.OnRender();
		}

		protected virtual void OnRender()
		{
			if (!ScreenApplication.RenderSuspended)
			{
				EventHandler handler = this.Render;

				if (null != handler)
				{
					handler(this, EventArgs.Empty);
				}

				foreach (ScreenControl control in this.Controls)
				{
					control.DoRender();
				}
			}
		}

		protected virtual void OnInitialize()
		{
			EventHandler handler = this.Initialize;

			if (null != handler)
			{
				handler(this, EventArgs.Empty);
			}
		}

		private void Controls_Cleared(object sender, ScreenControlCollectionClearedEventArgs e)
		{
			foreach (ScreenControl control in e.ClearedControls)
			{
				control.Parent = null;
			}
		}

		private void Controls_ControlRemoved(object sender, ScreenControlEventArgs e)
		{
			e.Control.Parent = null;
		}

		private void Controls_ControlAdded(object sender, ScreenControlEventArgs e)
		{
			e.Control.Parent = this;
		}

		public virtual void Invalidate()
		{
			this.DoRender();
		}

		public virtual void InvalidateScreen()
		{
			if (!ScreenApplication.RenderSuspended)
			{
				ScreenApplication.Instance.Screen.Invalidate();
			}
		}

		protected void SetSafeCursorPosition(int left, int top)
		{
			if (Console.BufferHeight <= top)
			{
				top = Console.BufferHeight - 1;
			}
			else if (top < 0)
			{
				top = 0;
			}

			if (Console.BufferWidth <= left)
			{
				left = Console.BufferWidth - 1;
			}
			else if (left < 0)
			{
				left = 0;
			}

			Console.SetCursorPosition(left, top);
		}
	}
}